<template>
  <div 
    class="gems-form-item"
    :class="{
      'is-error': validateStatus.state === 'error',
      'is-success': validateStatus.state ==='success',
      'is-loading': validateStatus.loading,
      'is-required': isRequired
    }"
  >
    <label class="gems-form-item__label">
      <slot name="label" :label="label">
        {{ label }}
      </slot>
    </label>
    <div class="gems-form-item__content">
      <!-- 提供给子组件的验证方法 -->
      <slot :validate="validate"/>
      <div class="gems-form-item__error-msg" v-if="validateStatus.state === 'error'">
        {{ validateStatus.errorMsg }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, inject, computed, provide, onMounted, onUnmounted } from 'vue'
import Schema from 'async-validator'
import type { FormItemProps, FormValidateFailure, FormItemContext, FormItemRule, ValidateStatus, FormItemInstance } from './types'
import { formContextKey, formItemContextKey } from './types'
import { isNil } from 'lodash-es';

defineOptions({
  name: 'GemsFormItem',
})

const props = defineProps<FormItemProps>()

const formContext = inject(formContextKey)
// 验证状态
const validateStatus: ValidateStatus = reactive({
  state: 'init',
  errorMsg: '',
  loading: false
})
// 初始值
let initialValue: any = null
// 拿到内部值和对应的验证规则
const innerValue = computed(() => {
  const model = formContext?.model
  if (model && props.prop && !isNil(model[props.prop])) {
    return model[props.prop]
  } else {
    return null
  }
})
const itemRules = computed(() => {
  const rules = formContext?.rules
  if (rules && props.prop && rules[props.prop]) {
    return rules[props.prop]
  } else {
    return []
  }
})

// 是否为必填项
const isRequired = computed(() => {
  const rules = itemRules.value as FormItemRule[]
  return rules.some(rule => rule.required)
})
// 获取trigger触发的验证规则
const getTriggeredRules = (trigger?: string) => {
  const rules = itemRules.value as FormItemRule[]
  if (rules) {
    return rules.filter(rule => {
      if (!rule.trigger || !trigger) {
        return true
      }
      return rule.trigger && rule.trigger === trigger
    })
  } else {
    return []
  }
}
// 使用验证规则对内部值进行校验
const validate = async (trigger?: string) => {
  const modelName = props.prop
  const triggeredRules = getTriggeredRules(trigger)
  // 没有触发的规则，直接返回true
  if (triggeredRules.length === 0) {
    return true
  }
  if (modelName) {
    const descriptor = {
      // 规则名--对应规则
      [modelName]: triggeredRules
    }
    const validator = new Schema(descriptor)
    validateStatus.loading = true
    return validator.validate({ [modelName]: innerValue.value })
    .then(() => {
       validateStatus.state = 'success'
    })
    .catch((e: FormValidateFailure) => {
       validateStatus.state = 'error'
       validateStatus.errorMsg = (e.errors && e.errors.length > 0) ? e.errors[0].message || '' : ''
       // 完整表单验证需要这个错误信息
       return Promise.reject(e)
    })
    .finally(() => {
       validateStatus.loading = false
    })
  }
}

// 清除表单项item验证状态
const clearValidate = () => {
  validateStatus.state = 'init'
  validateStatus.errorMsg = ''
  validateStatus.loading = false
}
// 重置表单项item内容
const resetField = () => {
  clearValidate()
  const model = formContext?.model
  if (model && props.prop && model[props.prop]) {
    model[props.prop] = initialValue
  }
}

// 将验证方法注入
const formItemContext: FormItemContext =reactive({
  validate: validate,
  prop: props.prop || '',
  clearValidate: clearValidate,
  resetField: resetField
})

provide(formItemContextKey, formItemContext)


// 向外暴露实例方法
defineExpose<FormItemInstance>({
  validateStatus: validateStatus,
  validate: validate,
  clearValidate: clearValidate,
  resetField: resetField
})

// 在挂载时将实例formItemContext添加上到formContext的items中
onMounted(() => {
  if (props.prop) {
    formContext?.addField(formItemContext)
    initialValue = innerValue.value
  }
})
onUnmounted(() => {
  formContext?.removeField(formItemContext)
})
</script>